package com.jwater.core.common.xml;

import java.util.ArrayList;
import java.util.List;

import com.jwater.core.common.param.ParamMap;
import com.jwater.core.common.param.ParamMapImpl;

import jwater.org.dom4j.Attribute;
import jwater.org.dom4j.Document;
import jwater.org.dom4j.Element;

/**
 * @description:
 * @author: jnner
 * @createDate: 2021/2/5
 * @version: 1.0
 */
public class XmlData extends ParamMapImpl {
    private static final long serialVersionUID = 3523216282045433346L;
    protected Document doc;

    public XmlData() {
    }

    public XmlData(Document doc) {
        this.doc = doc;
        parse();
    }

    public Document getDoc() {
        return doc;
    }

    public void setDoc(Document doc) {
        this.doc = doc;
        parse();
    }

    /**
     * @param path examples:user/password/a/b/j
     * @return
     */
    public Object getDataByPath(String path) {
        String[] items = path.split("/");
        Object data = this.getObject(items[0]);
        if (data == null) {
            return null;
        }
        for (int i = 1; i < items.length; i++) {
            data = ((ParamMap) data).getObject(items[i]);
            if (data == null) {
                return null;
            }
        }
        return data;
    }

    public ParamMap getParamMapByPath(String path) {
        return (ParamMap) getDataByPath(path);
    }

    /**
     * @param path
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<ParamMap> getParamMapsByPath(String path) {
        Object obj = getDataByPath(path);
        if (obj == null) {
            return null;
        }
        if (obj instanceof ParamMap) {
            List<ParamMap> list = new ArrayList<ParamMap>();
            list.add((ParamMap) obj);
            return list;
        }
        return (List<ParamMap>) obj;
    }

    /**
     *
     */
    protected void parse() {
        Element root = doc.getRootElement();
        ParamMap rootData = new ParamMapImpl();
        this.put(root.getName(), rootData);
        parseNode(root, rootData);
    }

    /**
     * 递归解析xml文件所有节点，保存到ParamMap对象中
     *
     * @param parent
     * @param parentData
     */
    @SuppressWarnings("unchecked")
    protected void parseNode(Element parent, ParamMap parentData) {
        List<Attribute> parentAttrs = parent.attributes();
        for (Attribute parentAttr : parentAttrs) {
            parentData.put(parentAttr.getName(), parentAttr.getData());
        }
        List<Element> elements = parent.elements();
        if (elements != null && !elements.isEmpty()) {
            for (Element element : elements) {
                ParamMap data = new ParamMapImpl();
                if (parentData.containsKey(element.getName())) {
                    Object obj = parentData.getObject(element.getName());
                    List<ParamMap> datas = null;
                    if (obj instanceof ParamMap) {
                        datas = new ArrayList<ParamMap>();
                        datas.add((ParamMap) obj);
                    } else if (obj instanceof List) {
                        datas = (List<ParamMap>) obj;
                    } else {
                        throw new XmlException(
                                "label name can not same with parent attribute name:" + element.getName());
                    }
                    datas.add(data);
                    parentData.put(element.getName(), datas);
                } else {
                    parentData.put(element.getName(), data);
                }
                parseNode(element, data);
            }
        }
    }
}
